var ge;
google.load("earth", "1");

function init() {
    /* Make sure we have a uid */
    if (typeof uid === 'undefined') {
        /* If we don't, we should be able to create one */
        window.addEvent('domready', make_user);
    }
    google.earth.createInstance('map3d', initCB, failureCB);
}

function initCB(instance) {
    ge = instance;
    /* Start the COP loading if we have a user.  If not, we'll do it as soon as we do */
    if (!(typeof uid === 'undefined')) {
        fetchKML(ge);
    }
    /* Set options */
    ge.getLayerRoot().enableLayerById(ge.LAYER_BORDERS, true);
    ge.getNavigationControl().setVisibility(ge.VISIBILITY_AUTO);
    opts = ge.getOptions()
    opts.setScaleLegendVisibility(true);
    opts.setStatusBarVisibility(true);
    opts.setOverviewMapVisibility(true);
    google.earth.addEventListener(ge.getWindow(), 'mousedown', mouseDownListener);
    google.earth.addEventListener(ge.getGlobe(), 'mousemove', mouseMoveListener);
    google.earth.addEventListener(ge.getWindow(), 'mouseup', mouseUpListener);
    google.earth.addEventListener(ge.getView(), 'viewchange', viewChangeListener);
    ge.getWindow().setVisibility(true);
    /*DEBUG*/
    // Get the current view
    var lookAt = ge.getView().copyAsLookAt(ge.ALTITUDE_ABSOLUTE);

    // Set new latitude and longitude values
    lookAt.setLatitude(2);
    lookAt.setLongitude(7);
    lookAt.setAltitude(2100000);
    lookAt.setRange(0);

    // Update the view in Google Earth
    ge.getView().setAbstractView(lookAt);
    myInit();
}

function failureCB(errorCode) {
}

function fetchKML(ge) {
    var href = "http://localhost:8080/cop.kml?uid="+uid;
    google.earth.fetchKml(ge, href, function(kmlobject) {
        if (kmlobject) {
            ge.getFeatures().appendChild(kmlobject);
        } else {
            alert("Failed to load KML (error 0201)");
        }
    });
}

/* True if view has remained unchanged since mouse went down */
var mouseDownViewUnchanged;

/* Gratuitously stolen from the documentation */
dragInfo = null;
function mouseDownListener(event) {
    /* Track view change state */
    mouseDownViewUnchanged = true;
    /* For object dragging */
    if (event.getTarget().getType() == 'KmlPlacemark' &&
    event.getTarget().getGeometry().getType() == 'KmlPoint') {
        var placemark = event.getTarget();
        dragInfo = {
            placemark: event.getTarget(),
            dragged: false
        };
    }
}

// Listen for mousemove on the globe.
function mouseMoveListener(event) {
    if (dragInfo) {
        event.preventDefault();
        var point = dragInfo.placemark.getGeometry();
        point.setLatitude(event.getLatitude());
        point.setLongitude(event.getLongitude());
        dragInfo.dragged = true;
    }
}

// Listen for mouseup on the window.
function mouseUpListener(event) {
    if (dragInfo) {
        if (dragInfo.dragged) {
            // If the placemark was dragged, prevent balloons from popping up.
            event.preventDefault();
            /* Tell the server */
            ObjectPlaced(event.getTarget());
        }
        dragInfo = null;
    /* For objectplacement */
    } else  if (event.getTarget() == ge.getGlobe()) {
        objectPlacementClickListener(event);
    }
}

/* Called if the view changes */
function viewChangeListener(event) {
    /* If the mouse is down, it'll be in a different place when it comes up */
    mouseDownViewUnchanged = false;
}

/* Listen for doubleclick on the globe */
function objectPlacementClickListener(event) {
    /* Don't fire if we're not placing anything */
    if (selectedButton.get("id") == "cancel_btn") {
        return;
    /* Also, don't fire if the view has changed since the mouse went down */
    } else if (mouseDownViewUnchanged == false) {
        return;
    }
    /* Tell the server */
    var object = selectedButton.get("id").slice(0,-4);
    var lat = event.getLatitude();
    var lon = event.getLongitude();
    var alt = event.getAltitude();
    var req = new Request({
        url:    "/newbuilding",
        data:   {"user":        uid,
                 "type":        object,
                 "lat":         lat,
                 "lon":         lon,
                 "alt":         alt,
        },
        onSuccess: function(responseText) {msgLine(responseText)},
        method: "get",
    });
    req.send();
    getCountry(lat,lon);
}

/* Hopefully get a country digraph for the coordinates */
/* Return ?? if no country found */
var geocoder = new google.maps.Geocoder();
var clickedCountryName = "??";
function getCountry(lat, lon) {
    /* Country to return */
    var latlon= new google.maps.LatLng(lat, lon);
    geocoder.geocode({'latLng': latlon}, function(results, status) {
        clickedCountryName = "??";
        /* Check the status */
        switch(status) {
            case google.maps.GeocoderStatus.OK:
                /* Check each result */
                for (var i = 0; i < results.length; i++) {
                    /* See if we get a country */
                    if (results[i].types.contains("country")) {
                        /* Check each address component */
                        for (var j = 0; j < results[i].address_components.length; j++) {
                            /* Check for a country digraph */
                            if (results[i].address_components[j].types.contains("country") &&
                                results[i].address_components[j].short_name.length == 2) {
                                /* Keep ahold of it */
                                clickedCountryName = results[i].address_components[j].short_name;
                            }
                        }
                    }
                }
                break;
            case google.maps.GeocoderStatus.ZERO_RESULTS:
                clickedCountryName = "??";
                break;
            default:
                alert("Geocoder returned " + status + " (error 0202)");
        }
        msgLine(clickedCountryName);
    });
}




/* Function to pass an object's location to the server */
function ObjectPlaced(obj) {
    var req = new Request({
        url:    "http://localhost:8080/movement",
        data:   {"id":  obj.getId(),
                 "lat": obj.getGeometry().getLatitude(),
                 "lon": obj.getGeometry().getLongitude(),
                 "alt": obj.getGeometry().getAltitude(),
                 "uid": uid,
        },
    });
    req.send();
}
google.setOnLoadCallback(init);

/* Button Callbacks */
var selectedButton = null;
var buttonClick = function(event) {
    /* Disable the appropriate button */
    selectedButton.erase("disabled");
    selectedButton = event.target;
    selectedButton.set("disabled", "disabled");
    /* Change the image following the cursor */
    buttonId = event.target.get("id");
    if (buttonId == "cancel_btn") {
        removeImageFollowingCursor();
    } else {
        /* TODO: Make a better way to make an icon */
        changeCursor("/icons/" + buttonId.slice(0,-4) + "iconred-16.png");
    }
};

/* Functions to attach an image to the cursor */

/* Change the cursor to an image */
var imageFollowingCursor = new Element('img');
var imageFollowingCursorPath = "";
var imageFollowingCursorActive = false;
/* Change (or start) the image following the cursor. */
function changeCursor(iconPath) {
    imageFollowingCursorPath = iconPath;
    if (!imageFollowingCursorActive) {
        window.addEvent('mousemove', changeCursorMouseMoveCallback);
        imageFollowingCursorActive = true;
    }
    window.fireEvent('mousemove');
}
function changeCursorMouseMoveCallback(event) {
    /* Get mouse coordinates */
    var mouseX = null;
    var mouseY = null;
    if (event != undefined && event.hasOwnProperty("page")) {
        mouseX = event.page.x;
        mouseY = event.page.y;
    } else {
        mouseX = mouseLocationX;
        mouseY = mouseLocationY;
    }

    var image = new Element('img', {
        src:    imageFollowingCursorPath,
        styles: {position:  'absolute',
                 /* TODO: Work out where to put the icon. */
                 top:        mouseY + 16,
                 left:       mouseX + 16,
                 "z-index": "4",
        }
    }).inject($(document.body), 'top');
    imageFollowingCursor.dispose();
    imageFollowingCursor = image;
}
/* Remove the image following the cursor */
function removeImageFollowingCursor() {
    if (imageFollowingCursorActive) {
        window.removeEvent("mousemove", changeCursorMouseMoveCallback);
        imageFollowingCursorActive = false;
    }
    imageFollowingCursor.dispose();
    imageFollowingCursor = new Element('img');
}

/* Event handler for keypresses */
function keyhandler(event) {
    switch (event.key) {
        /* Airbase */
        case 'b':
        case 'B':
            $("airbase_btn").click();
            break;
        /* Silo */
        case 'm':
        case 'M':
            $("silo_btn").click();
            break;
        /* Radar */
        case 'i':
        case 'I':
            $("radar_btn").click();
            break;
        /* Cancel */
        case 'esc':
            $("cancel_btn").click();
            break;
        default:
            break;
    }
}

/* Continuously track the mouse location */
var mouseLocationX = null;
var mouseLocationY = null;
function mouseTrackerCallback(event) {
    mouseLocationX = event.page.x;
    mouseLocationY = event.page.y;
}

/* Function to convert DD to DMS. Both functions take floats and return str */
function convertLat(dd) {
    var res = ddToDMS(dd);
    var dir = dd>0?"N":"S";
    res = res + dir;
    return res;
}
function convertLon(dd) {
    var res = ddToDMS(dd);
    var pad = Math.abs(dd)<100?"0":"";
    var dir = dd<0?"W":"E";
    res = pad + res + dir;
    return res;
}


/* Returns a string.  The calling function is responsible for appending an
an initial 0 and a direction (NSEW) */
function ddToDMS(dd) {
    dd = Math.abs(dd);
    var degrees = Math.floor(dd);
    var minutes = Math.round((dd-degrees) * 60);
    var dstr = degrees<10?"0":"";
    dstr = dstr + degrees;
    var mstr = minutes<10?"0":"";
    mstr = mstr + minutes;
    return dstr + mstr
}




function myInit() {
    /* Populate variables that need to wait until after the page loads */
    selectedButton = $("cancel_btn");
    $("controls").getChildren("BUTTON").each(function(el, ind, arr){
        el.addEvent('click', buttonClick);
    });
    $(document).addEvent("keyup", keyhandler);
    $(document).addEvent("mousemove", mouseTrackerCallback);
}

/* Sets the text of the message line */
function msgLine(text) {
    $("message").set("html", "<PRE>"+text+"</PRE>");
}